home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
ddj0897.zip
/
DAN0411.ZIP
/
FISTBUG.ASM
next >
Wrap
Assembly Source File
|
1997-05-04
|
34KB
|
824 lines
page 60,132
;-----------------------------------------------------------------------------
;
; FISTBUG
;
; Copyright (c) 1997-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;
; FISTBUG --
;
; If all you're interested in seeing is the source code which should be
; offered for academic and peer review, please refer to the subrutines
; 'FistTest16' and 'FistTest32.'
;
; Synopsis:
; This program tests for a bug in the Pentium Pro and Pentium II floating
; point unit. This program may be run on a variety of microprocessors
; from the 80286 on up. For a complete description of the bug, please refer
; to http://www.x86.org/secrets/Dan0411.html.
;
; To assemble this source code:
; * You will need Microsoft Macro Assembler, version 6.11d (though just about
; any other version of MASM will probably work). Borland TASM will probably
; work also.
; * Run the makefile using the 'nmake' utility supplied with MASM.
; * You may compile this without the nmake utility by invoking the command
; line:
; C: > ml /Fl fistbug.asm - to generate non-verbose version
; C: > ml /Fl /DVERBOSE fistbug.asm - to genrate verbose version
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Assembler directives
;-----------------------------------------------------------------------------
.xlist ; disable list file
.286
;-----------------------------------------------------------------------------
; Include file section
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Equates
;-----------------------------------------------------------------------------
FSW_IE equ 1 ; Status Word IE bit
;-----------------------------------------------------------------------------
; Macros
;-----------------------------------------------------------------------------
PRINT_PASS_FAIL MACRO
ifdef VERBOSE
pushf ; save results of comparison
mov ah,9 ; print string function ID
mov dx,offset PassMsg ; prepare for test passed
jnz @F ; test did pass
mov dx,offset FailMsg ; get address of failed message
@@: int 21h ; print message
popf ; restore flags
endif ; VERBOSE
ENDM
PRINT_MSG MACRO MSG
ifdef VERBOSE
mov ah,9
mov dx,offset MSG
int 21h
endif ; VERBOSE
ENDM
;-----------------------------------------------------------------------------
; 16-bit Floating point environment
;
; I intentionally chose a 16-bit floating point environment to allow this
; program to be run on the 80286 microprocessor.
;-----------------------------------------------------------------------------
FPU_Struct STRUCT
FCW dw ? ; Control word
FSW dw ? ; Status word
FTW dw ? ; Tag word
dw ? ; Floating point IP
dw ? ; Floating point CS
dw ? ; Operand offset
dw ? ; Operand selector
ST0 dt ? ; ST0
ST1 dt ? ; ST1
ST2 dt ? ; ST2
ST3 dt ? ; ST3
ST4 dt ? ; ST4
ST5 dt ? ; ST5
ST6 dt ? ; ST6
ST7 dt ? ; ST7
FPU_Struct ENDS
.list
;-----------------------------------------------------------------------------
; Dummy segments
;-----------------------------------------------------------------------------
INTSEG segment at 0
org 6*4
INT06 dd ?
INTSEG ends
;-----------------------------------------------------------------------------
; Data segment
;-----------------------------------------------------------------------------
_DATA segment use16 para public 'DATA'
;-----------------------------------------------------------------------------
; Instantiate the floating point environment structure. I might as well make
; this appear at the paragraph boundary of the data segment.
;-----------------------------------------------------------------------------
FENV FPU_Struct <>
;-----------------------------------------------------------------------------
; This is where the list of floating point numbers is stored. If you want
; to add to this list, simply insert a floating point number in the 16-bit
; section, or the 32-bit section, depending on what your needs are. For
; example, you may want to verify that positive numbers aren't affected by
; this bug. To do so, you could simply insert a line such as:
; dt 65536.0
; The operand doesn't need to be given in hex as my examples were. My
; examples were choosen in hex to easily demonstrate the boundary conditions
; of the Dan-0411 bug.
;
; If you insert new operands, you don't need to make any other program
; changes, but you will need to reassemble the source code. The program
; automatically adjust the nuber of test cases according to how many
; operands appear in the Op16 or Op32 list.
;-----------------------------------------------------------------------------
Op16 dt 0c06e8000000000000001h
dt 0c06e8000000000000010h
dt 0c06e8000000000000100h
dt 0c06e8000000000001000h
dt 0c06e8000000000010000h
dt 0c06e8000000000100000h
dt 0c06e8000000001000000h
dt 0c06e8000000010000000h
dt 0c06e8000000100000000h
dt 0c06e8000001000000000h
dt 0c06e8000010000000000h
dt 0c06e8000100000000000h
dt 0c06e80007fffffffffffh
N16 equ ($-Op16) / sizeof Op16
Op32 dt 0c05e8000000000000001h
dt 0c05e8000000000000010h
dt 0c05e8000000000000100h
dt 0c05e8000000000001000h
dt 0c05e8000000000010000h
dt 0c05e8000000000100000h
dt 0c05e8000000001000000h
dt 0c05e8000000010000000h
dt 0c05e800000007fffffffh
N32 equ ($-Op32) / sizeof Op32
;-----------------------------------------------------------------------------
; D16 and D32 listed below are the destinations for the FIST and FISTP
; (Floating-to-Integer Store) instructions. The StatusWord variable is used
; to collect the resultant status words for the four different test cases on
; each floating point operand. 'Results' is used to accumulate the results.
; At the end of this test, if any bit is set in 'Results' then the test is
; considered a failure, and you've got the Dan-0411 bug.
;-----------------------------------------------------------------------------
D16 dw 55aah
D32 dd 55aa55aah
StatusWord dw 4 dup (0)
Results dw 0 ; Cumulative results
;-----------------------------------------------------------------------------
; Misc data storage.
;-----------------------------------------------------------------------------
CPUIDVal dd 0 ; Results of CPUID instruction
OrigINT06 dd 0 ; Temp holding spot for INT06 vector
;-----------------------------------------------------------------------------
; String messages used for formatting the screen output
;-----------------------------------------------------------------------------
; 16-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP
; xxxxxxxxxxxxxxxxxx PASS PASS PASS PASS
HeaderMsg16 db " 16-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP",0dh,0ah,24h
HeaderMsg32 db " 32-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP",0dh,0ah,24h
ValueBuf db " ",24h
Spaces db " ",24h
PassMsg db " PASS ",24h
FailMsg db "**FAIL**",24h
CRLFMsg db 0dh,0ah,24h
PMMsg db "Running in protected mode (probably Windows). Results are most",0dh,0ah
db "reliable while running in real mode (booting clean to DOS).",0dh,0ah
db "I'll try running anyways.",0dh,0ah,24h
CPUIDMsg db "Microprocessor ID: "
FamilyString db "Unknown "
db " Vendor String: "
IDString db "Not Detected",0dh,0ah,24h
Dan0411Failed db "*** Dan-0411 bug found. ***",0dh,0ah,24h
Dan0411Passed db "Dan-0411 not found.",0dh,0ah,24h
_DATA ENDS
;-----------------------------------------------------------------------------
; Beginning of main code segment
;-----------------------------------------------------------------------------
_TEXT segment para public use16 'CODE'
ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
;-----------------------------------------------------------------------------
; Code starts here
; * Set up stack
;-----------------------------------------------------------------------------
FISTBUG proc far
mov ax,seg STACK ; setup stack segment
mov ss,ax
mov sp,sizeof StackPtr
xor ax,ax ; clear it
pushf
push ds ; save far return on stack
push ax
;-----------------------------------------------------------------------------
; * Disable interrupts during this test
; * Set up data segments
;-----------------------------------------------------------------------------
cli ; disable interrupts
mov ax,seg _DATA ; get data segment
mov ds,ax
mov es,ax
ifdef VERBOSE
;-----------------------------------------------------------------------------
; The purpoase of this section of code is to determine a few things about
; the target computer. I'll detect whether or not we're in protected mode
; (like running in a DOS-box of Windows) and print a message accordingly.
; Whether or not we're in protected mode shouldn't make any difference, as
; I'm not executing any priviledged instryctions.
;
; Also in this section, I check for the processor stepping information and
; vendor string. If present, I'll print this information to the screen.
;-----------------------------------------------------------------------------
; Test for protected mode
;-----------------------------------------------------------------------------
smsw ax ; get lower bits of CR0
test al,1 ; in protected mode?
jz @F ; nope
PRINT_MSG PMMsg ; print protected mode message
PRINT_MSG CRLFMsg ; print <CRLF>
;-----------------------------------------------------------------------------
; Install INT06 (Invalid opcode) exception handler
;-----------------------------------------------------------------------------
@@: push es ; save
mov ax,seg INTSEG
mov es,ax
mov ax,offset OurINT6 ; get pointer to our INT6 handler
mov dx,cs ; get our code segment
xchg ax,word ptr es:INT06 ; swap 'em
xchg dx,word ptr es:INT06[2] ; swap vector
mov word ptr OrigINT06,ax ; save original vector
mov word ptr OrigINT06[2],dx; vector now saved
pop es ; restore original segment
;-----------------------------------------------------------------------------
; Execute CPUID instruction and print results on string
;
; This is a real down-and-dirty way to detect CPUID. I've installed an
; invalid exception handler, and pointed DX to a return address in the case
; that an invalid opcode exception occurs. If we're an 80286, then the
; 'xor eax,eax' instruction will cause the invalid opcode fault. If we're
; running on a processor that doesn't support CPUID, the 'cpuid' instruction
; will cause the invalid opcode fault. In either case, if the fault occurs,
; execution continues beyond the processor detection code. At that point,
; the processor stepping information is printed anyways with a default
; response. If CPUID does work, then the default results are filled in with
; the appropriate CPUID return values.
;-----------------------------------------------------------------------------
.586
mov dx,offset @NoCPUID ; set destination location
xor eax,eax ; real dirty way to detect 80386+
cpuid ; try CPUID instruction
mov dword ptr IDString[0],ebx
mov dword ptr IDString[4],edx
mov dword ptr IDString[8],ecx
mov eax,1 ; do next level of CPUID
cpuid ; get processor stepping
mov CPUIDVal,eax ; save it
mov si,offset CPUIDVal ; get source of CPUID stepping
mov di,offset FamilyString ; get destination of string
mov cx,4 ; # of bytes to convert
call hex_string ; convert data
@NoCPUID:
.286
PRINT_MSG CPUIDMsg ; print CPUID message
PRINT_MSG CRLFMsg ; print <CRLF>
;-----------------------------------------------------------------------------
; Restore invalid opcode interrupt handler
;-----------------------------------------------------------------------------
push es ; save
mov ax,seg INTSEG
mov es,ax
mov ax,word ptr OrigINT06[0]; get pointer to our INT6 handler
mov dx,word ptr OrigINT06[2]; get our code segment
xchg ax,word ptr es:INT06 ; swap 'em
xchg dx,word ptr es:INT06[2] ; swap vector
pop es ; restore original segment
;-----------------------------------------------------------------------------
; Print header message
;-----------------------------------------------------------------------------
PRINT_MSG HeaderMsg16 ; print beginning header message
endif
;-----------------------------------------------------------------------------
; Time to start test
;-----------------------------------------------------------------------------
mov cx,N16 ; # of 16-bit operands to test
xor si,si ; Initialize index pointer to operands
@FistLoop16:
ifdef VERBOSE
;-----------------------------------------------------------------------------
; The purpose of this section is printing the 80-bit hex operands to the
; screen. Each 80-bit operand is converted to ASCII and printed on the
; screen.
;-----------------------------------------------------------------------------
push cx
push si
;-----------------------------------------------------------------------------
; * Convert data to ASCII
; * Print value on screen
;-----------------------------------------------------------------------------
lea si,Op16[si] ; get pointer to data
mov di,offset ValueBuf ; get output buffer
mov cx,sizeof Op16 ; get # of bytes to convert
call hex_string
PRINT_MSG ValueBuf ; print 10-byte hex value on screen
pop si
pop cx
endif ; VERBOSE
;-----------------------------------------------------------------------------
; Start test
;-----------------------------------------------------------------------------
call FistTest16 ; Check various form of executing
; FIST[P] and saving FSW
;-----------------------------------------------------------------------------
; This section tests for the results of each of the operand test cases.
; Each test case is checked for the FSW.IE flag set. A pass/fail message is
; printed if running in VERBOSE mode. Otherwise, results are collected in
; the 'Results' variable for processing at the end of the test.
;-----------------------------------------------------------------------------
; Check for results
;-----------------------------------------------------------------------------
push cx ; save current count
xor di,di
mov cx,4 ; # of results to check
;-----------------------------------------------------------------------------
; Check for FSW.IE. If set, indicate results. If VERBOSE, print to the
; screen (macros handle verbose mode printing). Iterate through each test
; case until finished.
;-----------------------------------------------------------------------------
Check16:
test StatusWord[di],FSW_IE ; check for correct exception
PRINT_PASS_FAIL
jnz @F ; yes, behavior correct
or Results,-1 ; set results to indicate failure
@@: add di,2 ; point to next datum
dec cx ; are we done yet?
jz @F ; yes
PRINT_MSG Spaces
jmp Check16
@@: PRINT_MSG CRLFMsg ; print <CRLF>
pop cx
add si,sizeof Op16
loop @FistLoop16
;-----------------------------------------------------------------------------
; Now done testing all 16-bit operands.
; Time to test 32-bit operands.
;-----------------------------------------------------------------------------
; Print header message
;-----------------------------------------------------------------------------
PRINT_MSG CRLFMsg ; print <CRLF>
PRINT_MSG HeaderMsg32 ; print header message for 32-bit test
;-----------------------------------------------------------------------------
; Put code here...
;-----------------------------------------------------------------------------
mov cx,N32 ; # of 32-bit operands to test
xor si,si ; Initialize index pointer to operands
@FistLoop32:
ifdef VERBOSE
;-----------------------------------------------------------------------------
; The purpose of this section is printing the 80-bit hex operands to the
; screen. Each 80-bit operand is converted to ASCII and printed on the
; screen.
;-----------------------------------------------------------------------------
push cx
push si
;-----------------------------------------------------------------------------
; * Convert data to ASCII
; * Print value on screen
;-----------------------------------------------------------------------------
lea si,Op32[si] ; get pointer to data
mov di,offset ValueBuf ; get output buffer
mov cx,sizeof Op32 ; get # of bytes to convert
call hex_string
PRINT_MSG ValueBuf ; print 10-byte data on screen
pop si
pop cx
endif ; VERBOSE
;-----------------------------------------------------------------------------
; Start test
;-----------------------------------------------------------------------------
call FistTest32 ; Check various form of executing
; FIST[P] and saving FSW
;-----------------------------------------------------------------------------
; This section tests for the results of each of the operand test cases.
; Each test case is checked for the FSW.IE flag set. A pass/fail message is
; printed if running in VERBOSE mode. Otherwise, results are collected in
; the 'Results' variable for processing at the end of the test.
;-----------------------------------------------------------------------------
; Check for results
;-----------------------------------------------------------------------------
push cx ; save current count
xor di,di
mov cx,4 ; # of results to check
;-----------------------------------------------------------------------------
; Check for FSW.IE. If set, indicate results. If VERBOSE, print to the
; screen (macros handle verbose mode printing). Iterate through each test
; case until finished.
;-----------------------------------------------------------------------------
Check32:
test StatusWord[di],FSW_IE ; check for correct exception
PRINT_PASS_FAIL
jnz @F ; yes, behavior correct
or Results,-1 ; set results to indicate failure
@@: add di,2 ; point to next datum
dec cx ; are we done yet?
jz @F ; yes
PRINT_MSG Spaces
jmp Check32
@@: PRINT_MSG CRLFMsg ; print <CRLF>
pop cx
add si,sizeof Op32
loop @FistLoop32
;-----------------------------------------------------------------------------
; Now done testing all 32-bit operands.
; Now let's print the final results of the test. Does your processor have
; the 'Dan-0411' bug? If so, the results are printed here.
;-----------------------------------------------------------------------------
mov ah,9 ; get function to print string
mov dx,offset CRLFMsg ; get pointer to CRLF message
int 21h
mov dx,offset Dan0411Passed ; prepare to pass
test Results,-1 ; anything fail?
jz @F ; nope
mov dx,offset Dan0411Failed ; get failed message
@@: int 21h
;-----------------------------------------------------------------------------
; Terminate and return to DOS.
;-----------------------------------------------------------------------------
iret ; return to DOS
FISTBUG endp
;-----------------------------------------------------------------------------
FistTest16 proc near
;-----------------------------------------------------------------------------
; FistTest16 checks four different ways of executing the FIST[P] instruction
; and storing the status word to memory. Before each sub-test is attempted,
; the floating point unit is re-initialized with the fninit instruction.
; The FPU re-initialization ensures that any pending ("sticky") floating point
; errors from the previous test will be cleared. This also guarantees that
; the each sub-tests is performed on a pristine FPU environment.
;
; The four test cases are as follows:
; 1) * Floating point load using FLD instruction
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;
; 2) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;
; 3) * Floating point load using FLD instruction
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
; 4) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
;-----------------------------------------------------------------------------
; Input: DS:SI = Index pointer to 80-bit floating point operand
; Output: StatusWord filled in with FPU status words for each test case.
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
xor di,di ; initialize pointer to results
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 1) * Floating point load using FLD instruction
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op16[si] ; load a value
fist D16
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next FSW results datum
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 2) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op16[si] ; load a value
fnsave FENV ; save a copy of environment
; does implicit fninit
frstor FENV ; restore FPU environment
fist D16
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next data value
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 3) * Floating point load using FLD instruction
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
;-----------------------------------------------------------------------------
fld Op16[si] ; load a value
fistp D16
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next data value
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 4) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op16[si] ; load a value
fnsave FENV ; save a copy of environment
; does implicit fninit
frstor FENV ; restore FPU environment
fistp D16
fnstsw StatusWord[di] ; save results
ret
FistTest16 endp
;-----------------------------------------------------------------------------
FistTest32 proc near
;-----------------------------------------------------------------------------
;
; FistTest32 checks four different ways of executing the FIST[P] instruction
; and storing the status word to memory. Before each sub-test is attempted,
; the floating point unit is re-initialized with the fninit instruction.
; The FPU re-initialization ensures that any pending ("sticky") floating point
; errors from the previous test will be cleared. This also guarantees that
; the each sub-tests is performed on a pristine FPU environment.
;
; The four test cases are as follows:
; 1) * Floating point load using FLD instruction
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;
; 2) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;
; 3) * Floating point load using FLD instruction
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
; 4) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
;-----------------------------------------------------------------------------
; Input: DS:SI = Index pointer to 80-bit floating point operand
; Output: StatusWord filled in with FPU status words for each test case.
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
xor di,di ; initialize pointer to results
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 1) * Floating point load using FLD instruction
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op32[si] ; load a value
fist D32
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next data value
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 2) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FIST instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op32[si] ; load a value
fnsave FENV ; save a copy of environment
; does implicit fninit
frstor FENV ; restore FPU environment
fist D32
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next data value
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 3) * Floating point load using FLD instruction
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;
;-----------------------------------------------------------------------------
fld Op32[si] ; load a value
fistp D32
fnstsw StatusWord[di] ; save results
;-----------------------------------------------------------------------------
; Restore pristine environment.
;-----------------------------------------------------------------------------
add di,2 ; point to next data value
fninit ; initialize floating point unit
;-----------------------------------------------------------------------------
; 4) * Floating point load using FLD instruction
; * Save floating point environment with FNSAVE instruction. This
; instruction has the side-effect of re-initializing the FPU state (a
; good thing).
; * Restore the FPU state with FRSTOR instruction. This ensures that
; the Dan-0411 error wasn't a byproduct of the FLD instruction.
; * Floating point store using FISTP instruction
; * Store status word using FNSTSW instruction.
;-----------------------------------------------------------------------------
fld Op32[si] ; load a value
fnsave FENV ; save a copy of environment
; does implicit fninit
frstor FENV ; restore FPU environment
fistp D32
fnstsw StatusWord[di] ; save results
ret
FistTest32 endp
;-----------------------------------------------------------------------------
; HEX_STRING: Convert a string of 8-bit hex numbers to ASCII.
; Input: DS:SI = Pointer to hex data
; ES:DI = Buffer to get output
; CX = # of bytes to convert
; Output: ES:DI = Filled in w/ ASCII hex#
;-----------------------------------------------------------------------------
Hex_String proc near
;-----------------------------------------------------------------------------
jcxz @Hex_str_exit ; go split
push ax ; [bp][0ah]
push cx ; [bp][8]
push dx ; [bp][6]
push si ; [bp][4]
push di ; [bp][2]
push bp ; [bp]
mov bp,sp
add si,cx
@@: dec si
mov al,ds:[si] ; get hex digit
mov dl,al
mov cl,4 ; shift count
rol dl,cl
mov al,dl ; save it
and al,0fh ; keep low nibble
daa
add al,0f0h
adc al,40h ; here is the ASCII
stosb ; save it
mov cl,4 ; shift count
rol dl,cl
mov al,dl ; save it
and al,0fh ; keep low nibble
daa
add al,0f0h
adc al,40h ; here is the ASCII
stosb ; save it
dec word ptr [bp][8] ; are we done yet?
jnz @B
pop bp
pop di
pop si
pop dx
pop cx
pop ax
@Hex_str_exit:
ret
Hex_String endp
;-----------------------------------------------------------------------------
; This is a real down-and-dirty invalid opcode exception handler. All this
; handler does, is take the value in DX and use it as the return address.
;-----------------------------------------------------------------------------
; Input: DX = Return address
; Output: None
;-----------------------------------------------------------------------------
OurINT6 proc far
pop ax ; get IP from stack
mov ax,dx ; point to return address
push ax ; save it
iret ; go split
OurINT6 endp
_TEXT ENDS
STACK segment para public 'STACK'
;-----------------------------------------------------------------------------
; Stack segment
;-----------------------------------------------------------------------------
StackPtr db 400h dup (?)
STACK ends
end FISTBUG